#ifndef __Keyboard_hpp__
#define __Keyboard_hpp__

#include "Pointer.hpp"
#include "Singleton.hpp"

namespace ge {

GE_DECLARE_CLASS( Keyboard );

//----------------------------------------------------------------------------//
// Keyboard
//----------------------------------------------------------------------------//

class Keyboard : public virtual ReferenceCounted, public Singleton< Keyboard >
{

 friend class Device;
 friend class Observer;

 public:

     enum Key
     {
          Key_Unknown = 0,
          Key_F1 = 0x70,
          Key_F2,
          Key_F3,
          Key_F4,
          Key_F5,
          Key_F6, 
          Key_F7, 
          Key_F8, 
          Key_F9,  
          Key_F10, 
          Key_F11, 
          Key_F12, 
          Key_0 = 0x30,   
          Key_1,   
          Key_2,    
          Key_3,   
          Key_4,   
          Key_5,   
          Key_6,   
          Key_7,   
          Key_8,   
          Key_9,   
          Key_A = 0x41,   
          Key_B,   
          Key_C,  
          Key_D,  
          Key_E,  
          Key_F,  
          Key_G,   
          Key_H,  
          Key_I,  
          Key_J,  
          Key_K,  
          Key_L,  
          Key_M,  
          Key_N,  
          Key_O,  
          Key_P, 
          Key_Q, 
          Key_R,  
          Key_S,  
          Key_T, 
          Key_U,  
          Key_V, 
          Key_W,  
          Key_X,  
          Key_Y,  
          Key_Z, 
          Key_Numpad_0 = 0x60,  
          Key_Numpad_1,  
          Key_Numpad_2,  
          Key_Numpad_3,  
          Key_Numpad_4,  
          Key_Numpad_5,  
          Key_Numpad_6,  
          Key_Numpad_7,  
          Key_Numpad_8,  
          Key_Numpad_9,  
          Key_Caps_Lock = 0x14,  
          Key_Scroll_Lock = 0x91,
          Key_Numpad_Lock = 0x90, 
          Key_LeftShift = 0xa0, // input msg = VK_SHIFT
          Key_RightShift = 0xa1, // input msg = VK_SHIFT 
          Key_LeftCtrl = 0xa2, // input msg = VK_CONTROL 
          Key_RightCtrl = 0xa3, // input msg = VK_CONTROL  
          Key_LeftAlt = 0xa4, // input msg = VK_MENU   
          Key_RightAlt = 0xa5, // input msg = VK_MENU  
          Key_PrintScreen = 0x2c,
          Key_Pause = 0x13, 
          Key_Escape = 0x1b,  
          Key_Enter = 0x0d,   
          Key_Backspace = 0x08,  
          Key_Tab = 0x09,       
          Key_Space = 0x20,   
          Key_LeftSystem = 0x5b,
          Key_RightSystem = 0x5c,
          Key_LeftContextMenu = 0x8a, // non-native WinAPI, input msg = VK_APPS
          Key_RightContextMenu = 0x8b, // non-native WinAPI, input msg = VK_APPS   
          Key_Insert = 0x2d,    
          Key_Delete = 0x2e,   
          Key_Home = 0x24,   
          Key_End = 0x23,    
          Key_Page_Up = 0x21,
          Key_Page_Down = 0x22, 
          Key_Left = 0x25,  
          Key_Right = 0x27, 
          Key_Up = 0x26,  
          Key_Down = 0x28,
          Key_Numpad_Divide = 0x6f, 
          Key_Numpad_Multiply = 0x6a,
          Key_Numpad_Add = 0x6b,     
          Key_Numpad_Subtract = 0x6d,
          Key_Numpad_Decimal = 0x6e, 
          Key_Numpad_Enter = 0x88,  // non-native WinAPI, input msg = VK_MENU  
          Key_Tilde = 0xc0,             // ` ~     
          Key_Plus = 0xbb,               // = + 
          Key_Minus = 0xbd,          // - _
          Key_Comma = 0xbc,             // , <
          Key_Period = 0xbe,            // . >
          Key_ForwardSlash = 0xbf,     // / ?
          Key_BackSlash = 0xdc,        // \ |
          Key_LeftBracket = 0xdb,      // [ {
          Key_RightBracket = 0xdd,     // ] }
          Key_Semicolon = 0xba,         // ; :
          Key_Apostrophe = 0xde,        // ' "
          Key_Browser_Back    =    0xa6,
          Key_Browser_Forward =    0xa7,
          Key_Browser_Refresh =    0xa8,
          Key_Browser_Stop    =    0xa9,
          Key_Browser_Search  =    0xaa,
          Key_Browser_Favorites =  0xab,
          Key_Browser_Home      =  0xac,
          Key_Volume_Mute      =   0xad,
          Key_Volume_Down      =   0xae,
          Key_Volume_Up        =   0xaf,
          Key_Media_NextTrack  =  0xb0,
          Key_Media_PrevTrack  =  0xb1,
          Key_Media_Stop        =  0xb2,
          Key_Media_PlayPause  =  0xb3,
          Key_Max = 0xff,
     };

     enum CtrlKey
     {
          CtrlKey_LeftShift = 0x1,
          CtrlKey_RightShift = 0x2,
          CtrlKey_LeftAlt = 0x4,
          CtrlKey_RightAlt = 0x8,
          CtrlKey_LeftCtrl = 0x10,
          CtrlKey_RightCtrl = 0x20,
          CtrlKey_Shift = CtrlKey_LeftShift | CtrlKey_RightShift,
          CtrlKey_Alt = CtrlKey_LeftAlt | CtrlKey_RightAlt,
          CtrlKey_Ctrl = CtrlKey_LeftCtrl | CtrlKey_RightCtrl,
          CtrlKey_Caps_Lock = 0x40,
          CtrlKey_Scroll_Lock = 0x80,
          CtrlKey_Numpad_Lock = 0x100,
     };

     struct KeyState
     {
          uint prev_state;
          uint current_state;
     };

     class Observer : public virtual ReferenceCounted
     {
      public:

          Observer( void )
          {
          }

          // _action == 0 - up, _action == 1 - down, _action > 1 - repeat
          virtual void OnKeyEvent( Keyboard::Key _key, uint _action, char _ch ) 
          {
          }

          virtual void OnKeyboardFocusEvent( bool _focus ) 
          {
          }

          virtual void ObserveKeyboard( bool _new_status = true )
          {
               if( m_keyboard_is_observed != _new_status )
               {
                    if( _new_status ) Keyboard::_AddObserver( this );
                    else Keyboard::_RemoveObserver( this );
                    m_keyboard_is_observed = _new_status;
               }
          }

      protected:

          virtual ~Observer( void )
          {
          }

      private:

          bool m_keyboard_is_observed;
     };
     GE_DECLARE_PTR( Observer );

     static bool IsValidKey( Key _key );

 protected:

     static void _AddObserver( Observer* _observer );

     static void _RemoveObserver( Observer* _observer );
     
     //bool m_supported_keys[Key_Max];

     
};

} // namespace ge

#endif//__Keyboard_hpp__
